/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include "../绘图框架.h"

#include "Core/Vk结构声明.h"
#include "帧缓存/S_Vk帧缓存.h"
#include "帧缓存/绘制命令缓存.h"

//#include "线管/着色器.h"
#include "线管/布局描述.h"

#include "线管绘制.h"


#define VK_API_VERSION_1_3
#include <Windows.h>
#include <vulkan/vulkan.h>


#include <vector>
#include <map>



typedef struct {
	VkPhysicalDeviceMemoryProperties		m_内存属性;
	VkPhysicalDeviceProperties				m_设备属性;

	VkPhysicalDeviceRayTracingPropertiesNV	m_光追设备属性;

	uint32								m_多次采样最大值;
	uint32								m_最大几何输出顶点;
	uint32								m_3D纹理最大分辨率;
	uint32								m_nonCoherentAtomSize;
	bool								m_支持光追;
}S_物理设备属性;

struct S_vk_window {
	DEF_VK_窗口交换面

	S_纹理**	m_交换面颜色缓存;
	uint32		m_交换链ID;
};

typedef struct {
	VkPipelineLayout m_图像绘制管线布局;
}S_2D绘图管线布局集;





struct S_VK框架 : public S_绘图框架 {
	VkInstance										m_Instance;

	vector<VkPhysicalDeviceMemoryProperties>		m_内存属性组;
	vector<VkPhysicalDeviceProperties>				m_物理设备属性;
	vector<VkPhysicalDeviceRayTracingPropertiesNV>	m_物理光追设备属性;

	map<uint32, vector<VkQueueFamilyProperties>>	m_列队家族;


	


	vector<uint32>									m_绘图GPU;
	vector<uint32>									m_光追GPU;
	map<uint32, vector<S_Vk逻辑设备>>				m_逻辑设备;
	//vector<VkPipeline>								m_线管;
	//vector<string>								m_扩展名称;
	//vector<string>								m_设备名称;
	VkAllocationCallbacks*							m_allocator = VK_NULL_HANDLE;

	bool											m_开启光追;


	//光追API
	//PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
	PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructure;
	PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructure;
	PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructures;
	PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructures;
	PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizes;
	PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddress;
	PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelines;
	PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandles;
	PFN_vkCmdTraceRaysKHR vkCmdTraceRays;

	PFN_vkCmdSetSampleLocationsEXT vkCmdSetSampleLocationsEXT;



	S_VK框架();
	~S_VK框架();

	//bool f_initVK();
	bool f_releaseVK();


	bool	f_创建实例();
	bool	f_枚举物理设备(const vector<const char*>& 光追扩展);
	
	int32		f_选择列队族(vector<VkQueueFamilyProperties>& 列队族, uint32 flags);
	VkFormat	f_取设备支持像素格式(VkPhysicalDevice& 物理设备, VkSurfaceKHR& surface);



	virtual S_物理设备	f_取物理设备(uint8 id);

	S_逻辑设备	f_创建图形逻辑设备(S_物理设备& dev, bool 是否有光追支持);
	S_逻辑设备	f_创建计算逻辑设备(S_逻辑设备& dev);
	bool			f_创建窗口绘制面(S_设备环境& dev, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样);
	//bool			f_创建窗口绘制面(void* 绘图设备, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样);
	bool			f_创建同步围栏(S_逻辑设备& 逻辑dev);
	
	bool		f_创建交换链(void* 绘图设备, ivec2 size, VkSwapchainKHR old_swapchain);
	void		f_创建交换链绘制缓存(S_设备环境& dev, E_MS次数 采样);
	void		f_重置交换链(S_设备环境& dev, ivec2 size, E_MS次数 采样);



	bool		f_销毁交换链(S_Vk逻辑设备& dev);
	bool		f_销毁命令列队(S_Vk逻辑设备& dev);
	bool		f_销毁逻辑设备(vector<S_Vk逻辑设备>& devs);
	//bool		f_销毁物理设备();
	bool		f_销毁实例(VkInstance& instance);

	bool		f_绘制(S_逻辑设备& dev);
	void		f_alloc(S_逻辑设备& dev);
	void		f_End(S_逻辑设备& dev);
	void		f_beginRender(S_渲染环境* 绘图设备配置);
	void		f_endRender(S_渲染环境* 绘图设备配置);
	//void f_mainLoop();
private:
	vector<VkQueueFamilyProperties>	f_罗列物理设备列队家族(VkPhysicalDevice& 物理设备);

	bool		m_是否有光追支持;


	

};


typedef struct {
	DEF_渲染环境着色管线

	S_Vk帧缓存*		 m_交换链帧缓存;
	VkDevice         m_设备;
	VkPhysicalDevice m_物理设备;
	



	S_VK框架* m_绘图框架;
	E_MS次数  m_采样数;

	uvec2	绘制面大小;
	uint32	绘图列队家族Offset;
	uint32	交换链列队家族Offset;




	
	VkRenderPass	m_窗口UI渲染通道;
	VkRenderPass	m_窗口UI合成通道;

	VkRenderPass	m_场景渲染通道;
	VkRenderPass	m_阴影渲染通道;
	VkRenderPass	m_环境渲染通道;
	VkRenderPass	m_几何缓存渲染通道;


	VkSwapchainKHR	m_交换链;
	VkSurfaceKHR	m_绘制面;
	VkSemaphore		m_图像获取信号量;


	VkPhysicalDeviceProperties			m_设备属性;
	VkPhysicalDeviceMemoryProperties	m_内存属性;


	VkSubmitInfo				m_命令提交信息;
	//VkRenderPassBeginInfo		m_开始渲染信息;
	VkCommandBufferBeginInfo	m_命令开始信息;


	uint32					m_当前帧ID;
	uint32					m_列队ID;

	VkQueue*				m_图形列队;
	VkCommandPool			m_命令缓存池;
	VkCommandBuffer			m_命令缓存;
	VkFence					m_同步围栏;


	//==================== 多线程环境 ===========================
	VkCommandBuffer					m_二级命令缓存[64];
	VkCommandPool					m_二级命令管道;
	uint16							m_命令缓存数;

	VkCommandBufferBeginInfo		m_二级渲染开始信息;
	VkCommandBufferInheritanceInfo	m_二级命令缓存继承信息;




	

	//废弃
	VkFormat		m_颜色图像格式;
	VkFormat		m_深度图像格式;
	//VkClearValue	m_背景清除值[4];

} S_VK渲染环境;




Inline S_VK渲染环境*	f_vk_get绘图环境(S_设备环境& ctx) { return (S_VK渲染环境*)ctx.m_绘图环境; }
Inline S_VK框架*		f_vk_get绘图框架(S_设备环境& ctx) { return (S_VK框架*)ctx.m_绘图框架; }
Inline VkDevice			f_vk_getDevice(S_设备环境& ctx) { return ((VkDevice)ctx.m_逻辑设备.设备); }
Inline VkDescriptorSet	f_vk_get着色参数设置(S_结构对象* ds){ return ((S_GPU参数设置描述*)ds)->m_DescriptorSet;}
Inline S_物理设备属性&	f_vk_get物理设备属性(S_设备环境& ctx) { return *((S_物理设备属性*)ctx.m_物理设备.物理设备属性); }

void f_vkFrame_初始化光追函数指针(S_VK框架* VK框架, VkDevice 设备);


void			f_vk创建命令缓存池(S_VK渲染环境* 绘图设备);
VkCommandBuffer	f_vk创建命令缓存(S_VK渲染环境* 绘图设备, uint32 num = 1, bool 创建新池 = false);
void            f_vk销毁命令缓存(S_VK渲染环境* 绘图设备, VkCommandBuffer cmd);

void			f_vk绑定命令缓存(S_VK渲染环境* 绘图设备, VkCommandBuffer cmd, bool 重置命令缓存 = false);
void			f_vk刷新命令缓存(S_VK渲染环境* 绘图设备, VkCommandBuffer cmd, bool 释放命令缓存 = false);


Inline S_结构指针 f_vk创建Fence(S_VK渲染环境* 绘图环境) {
	VkFenceCreateInfo fenceCreateInfo{};
	fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
	fenceCreateInfo.flags = 0;

	VkFence fence;
	vkCreateFence(绘图环境->m_设备, &fenceCreateInfo, nullptr, &fence);
	return (S_结构指针)fence;
}

Inline void f_vk销毁Fence(S_VK渲染环境* 绘图环境, S_结构指针 fence) {
	vkDestroyFence(绘图环境->m_设备, (VkFence)fence, nullptr);
}

void	f_vk创建命令缓存(void* 绘图设备, uint32 池ID, uint32 num = 1);
void	f_vk创建同步围栏(void* 绘图设备);






//inline VkDescriptorType f_vk_get缓存布局类型(E_板载缓存类型 缓存类型) {
//	switch (缓存类型) {
//		case E_板载缓存类型::e_UBO:
//			return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
//			break;
//		case E_板载缓存类型::e_VBO:
//		case E_板载缓存类型::e_SSBO:
//			return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
//			break;
//		case E_板载缓存类型::e_SSBOd:
//			return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
//			//case E_板载缓存类型::e_UBO:
//			//	return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
//
//		
//		case E_板载缓存类型::e_IMAGE:
//		case E_板载缓存类型::e_IMAGE_Array: 
//		case E_板载缓存类型::e_纹理储存_Array: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
//
//		case E_板载缓存类型::e_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER;
//		case E_板载缓存类型::e_SAMPLER_Array:return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
//		//case E_板载缓存类型::e_IMAGE_SAMPLER: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
//		case E_板载缓存类型::e_IMAGE_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
//
//		case E_板载缓存类型::e_光追BVH: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
//		default:
//			break;
//	}
//
//	return VK_DESCRIPTOR_TYPE_MAX_ENUM;
//}



Inline uint32 f_vk_get参数布局着色阶段(E_着色阶段 阶段) {
	
	switch (阶段) {
	case E_着色阶段::e_顶点着色:
		return VK_SHADER_STAGE_VERTEX_BIT;

	case E_着色阶段::e_细分控制着色:
		return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
	
	case E_着色阶段::e_细分着色:
		return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
	
	case E_着色阶段::e_几何着色:
		return VK_SHADER_STAGE_GEOMETRY_BIT;
	
	case E_着色阶段::e_像素着色:
		return VK_SHADER_STAGE_FRAGMENT_BIT;
	
	case E_着色阶段::e_计算着色:
		return VK_SHADER_STAGE_COMPUTE_BIT;
	
	case E_着色阶段::e_光追射线生成:
		return VK_SHADER_STAGE_RAYGEN_BIT_KHR;
	
	case E_着色阶段::e_光追忽略相交:
		return VK_SHADER_STAGE_MISS_BIT_KHR;
	
	case E_着色阶段::e_光追AABB:
		return VK_SHADER_STAGE_INTERSECTION_BIT_KHR;

	case E_着色阶段::e_光追最近相交:
		return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;

	case E_着色阶段::e_光追回调:
		return VK_SHADER_STAGE_CALLABLE_BIT_KHR;
	}

	return 0;
}

template<E_管线槽 阶段>
Inline uint32 f_vk_get参数布局着色阶段() {
	if constexpr (阶段 == E_着色阶段::e_顶点着色) {
		return VK_SHADER_STAGE_VERTEX_BIT;
	}
	else if constexpr (阶段 == E_着色阶段::e_细分控制着色) {
		return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
	}
	else if constexpr (阶段 == E_着色阶段::e_细分着色) {
		return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
	}
	else if constexpr (阶段 == E_着色阶段::e_几何着色) {
		return VK_SHADER_STAGE_GEOMETRY_BIT;
	}
	else if constexpr (阶段 == E_着色阶段::e_像素着色) {
		return VK_SHADER_STAGE_FRAGMENT_BIT;
	}
	else if constexpr (阶段 == E_着色阶段::e_光追射线生成) {
		return VK_SHADER_STAGE_RAYGEN_BIT_KHR;
	}
	else if constexpr (阶段 == E_着色阶段::e_光追忽略相交) {
		return VK_SHADER_STAGE_MISS_BIT_KHR;
	}
	else if constexpr (阶段 == E_着色阶段::e_光追AABB) {
		return VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
	}
	else if constexpr (阶段 == E_着色阶段::e_光追最近相交) {
		return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
	}
	else if constexpr (阶段 == E_着色阶段::e_光追回调) {
		return VK_SHADER_STAGE_CALLABLE_BIT_KHR;
	}
	return 0;
}



void f_df_绑定管线(VkCommandBuffer 命令缓存, S_着色线管* 着色线管, E_管线槽 线管槽);
void f_vk_绑定管线(VkCommandBuffer 命令缓存, S_着色线管* 着色线管, E_管线槽 线管槽);

S_vk_window*	f_df_win32Surface(S_设备环境& ctx, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样);
void			f_df_release_win32Surface(S_设备环境& ctx, S_WindowSurface* surface);
void			f_df_win32Surface_resize(S_设备环境& ctx, S_WindowSurface* surface, uvec2 size);

void f_df_render_begin(S_WindowSurface* surface, S_渲染环境* 渲染环境);
void f_df_render_end(S_WindowSurface* surface, S_渲染环境* 渲染环境);



